package top.wyloop.fasthome.module.system.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import top.wyloop.fasthome.exception.SystemException;
import top.wyloop.fasthome.logger.ControllerLog;
import top.wyloop.fasthome.module.system.model.entity.User;
import top.wyloop.fasthome.module.system.service.CaptchaService;
import top.wyloop.fasthome.module.system.service.UserService;
import top.wyloop.fasthome.result.RetResult;

import java.io.File;
import java.util.Date;

/**
 * @author Wyatt6
 * @date 2025/5/9
 */
@Slf4j
@RestController
@RequestMapping("/api/system/user")
public class UserController {
    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private UserService userService;

    @ControllerLog("注册新用户API")
    @PostMapping("/register")
    public RetResult register(@RequestBody User input) {
        Assert.notNull(input, "输入数据为空");
        Assert.hasText(input.getCaptchaKey(), "验证码KEY为空");
        Assert.hasText(input.getCaptcha(), "验证码为空");
        Assert.hasText(input.getUsername(), "用户名为空");
        Assert.hasText(input.getPassword(), "密码为空");

        String captchaKey = input.getCaptchaKey().trim();
        String captcha = input.getCaptcha().trim();
        String username = input.getUsername().trim();
        String password = input.getPassword().trim();
        log.info("请求参数: captchaKey=[{}], captcha=[{}], username=[{}]", captchaKey, captcha, username);

        captchaService.verifyCaptcha(captchaKey, captcha);
        if (!userService.checkUsernameFormat(username)) {
            throw new SystemException("用户名格式错误");
        }
        if (!userService.checkPasswordFormat(password)) {
            throw new SystemException("密码格式错误");
        }
        User user = userService.createUser(username, password);

        return new RetResult().success();
    }

    @ControllerLog("用户登录API")
    @PostMapping("/login")
    public RetResult login(@RequestBody User input) {
        Assert.notNull(input, "输入数据为空");
        Assert.hasText(input.getCaptchaKey(), "验证码KEY为空");
        Assert.hasText(input.getCaptcha(), "验证码为空");
        Assert.hasText(input.getUsername(), "用户名为空");
        Assert.hasText(input.getPassword(), "密码为空");

        String captchaKey = input.getCaptchaKey().trim();
        String captcha = input.getCaptcha().trim();
        String username = input.getUsername();
        String password = input.getPassword();
        log.info("请求参数: captchaKey=[{}], captcha=[{}], username=[{}]", captchaKey, captcha, username);

        captchaService.verifyCaptcha(captchaKey, captcha);
        if (!userService.checkUsernameFormat(username)) {
            throw new SystemException("用户名格式错误");
        }
        if (!userService.checkPasswordFormat(password)) {
            throw new SystemException("密码格式错误");
        }

        User user = userService.authentication(username, password);
        log.info("登录：Sa-Token框架自动生成token并缓存");
        StpUtil.login(user.getId());
        log.info("loginId=[{}]", StpUtil.getLoginId());
        log.info("token=[{}]", StpUtil.getTokenValue());
        log.info("sessionId=[{}]", StpUtil.getSession().getId());

        log.info("更新用户最近登录时间服务");
        User data = new User();
        data.setId(user.getId());
        data.setLastLoginTime(new Date());
        user = userService.updateUserAttributesByIdRepeatableRead(data);

        log.info("用户数据脱敏");
        user.setPassword(null);
        user.setSalt(null);

        return new RetResult().success()
                .addData("user", user)
                .addData("token", StpUtil.getTokenValue())
                .addData("tokenExpiredTime", System.currentTimeMillis() + StpUtil.getTokenTimeout() * 1000);
    }

    @ControllerLog("退出登录API")
    @SaCheckLogin
    @GetMapping("/logout")
    public RetResult logout() {
        log.info("token=[{}]", StpUtil.getTokenValue());
        log.info("loginId=[{}]", StpUtil.getLoginIdAsLong());
        StpUtil.logout();
        log.info("退出登录成功");
        return new RetResult().success();
    }

    @ControllerLog("修改密码API")
    @SaCheckLogin
    @PostMapping("/changePassword")
    public RetResult changePassword(@RequestBody User input) {
        Assert.notNull(input, "输入数据为空");
        Assert.hasText(input.getPassword(), "旧密码为空");
        Assert.hasText(input.getNewPassword(), "新密码为空");

        log.info("检查新、旧密码格式");
        if (!userService.checkPasswordFormat(input.getPassword())) {
            throw new SystemException("旧密码格式错误");
        }
        if (!userService.checkPasswordFormat(input.getNewPassword())) {
            throw new SystemException("新密码格式错误");
        }

        log.info("loginId=[{}]", StpUtil.getLoginId());
        userService.changePassword(StpUtil.getLoginIdAsLong(), input.getPassword(), input.getNewPassword());
        log.info("密码修改成功后踢下线重新登陆");
        StpUtil.kickout(StpUtil.getLoginId());
        return new RetResult().success()
                .setMessage("密码修改成功，请重新登陆")
                .addData("code", 301).addData("target", "login");
    }

    @ControllerLog("设置昵称API")
    @SaCheckLogin
    @GetMapping("/setNickname")
    public RetResult setNickname(@RequestParam("nickname") String nickname) {
        Assert.hasText(nickname, "昵称为空");
        log.info("请求参数: nickname=[{}]", nickname.trim());

        User data = new User();
        data.setId(StpUtil.getLoginIdAsLong());
        data.setNickname(nickname.trim());
        userService.updateUserAttributesByIdSerializable(data);
        return new RetResult().success();
    }

    @ControllerLog("上传头像API")
    @SaCheckLogin
    @PostMapping("/uploadAvatar")
    public RetResult uploadAvatar(@RequestParam("file") MultipartFile avatar) {
        Assert.notNull(avatar, "头像为空");

        log.info("头像存储目录不存在则创建目录");
        File avatarDir = new File("upload/avatar");
        if (!avatarDir.exists()) {
            avatarDir.mkdirs();
        }

        long id = StpUtil.getLoginIdAsLong();
        long timestamp = System.currentTimeMillis();
        String suffix = avatar.getContentType().trim().toLowerCase().substring(6);

        if (!(suffix.equals("jpeg") || suffix.equals("png"))) {
            throw new SystemException("头像格式错误，只支持jpg/jpeg或png格式");
        }
        if (avatar.getSize() > 1024 * 512) {
            throw new SystemException("头像尺寸过大，须不大于512KB");
        }

        String avatarName = id + "_" + timestamp + "." + suffix;
        File avatarFile = new File(avatarDir + "/" + avatarName);
        log.info("头像保存路径: {}", avatarFile.getAbsolutePath());

        try {
            log.info("保存头像文件");
            avatar.transferTo(avatarFile.getAbsoluteFile());    // transferTo要求用绝对路径

            log.info("头像文件路径写入到数据库");
            User data = new User();
            data.setId(StpUtil.getLoginIdAsLong());
            data.setAvatarName(avatarName);
            userService.updateUserAttributesByIdRepeatableRead(data);

            String avatarUri = "/api/system/user/avatar/" + avatarName;
            return new RetResult().success().addData("avatarUri", avatarUri);
        } catch (Exception e) {
            throw new SystemException(e.getMessage());
        }
    }
}
